/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2ImageIrr.cpp 28 2012-07-28 17:03:06Z trzntaat $
 * $Revision: 28 $
 */

#include <math.h>
#include "Turs2.h"

#ifdef T2_USE_IRR

#include <assert.h>

using namespace irr;

namespace turska
{


ImageIrr::ImageIrr(GraphicsIrr *graphics,
                   UI32 width, UI32 height, UI32 flags,
                   irr::video::ITexture *texture, const irr::core::vector2df *uv) :
    Image(width, height, IDM_NORMAL, flags),
    mGraphics(graphics),
    mDriver(0),
    mTexture(texture),
    mHalfWidth((F32)width / 2.0f),
    mHalfHeight((F32)height / 2.0f),
    mTargetWidth((F32)width),
    mTargetHeight((F32)height),
    mAngle(0),
    mScaleX(1), mScaleY(1),
    mUsingExplicitTargetSize(false)
{
    assert(graphics);
    if (graphics)
        mDriver = graphics->getIrrDevice()->getVideoDriver();
    mColor.set(0xffffffff);
    mUV[0].set(uv[0]);
    mUV[1].set(uv[1]);
    if (texture)
        texture->grab();
}


ImageIrr::~ImageIrr()
{
    if (mTexture)
        mTexture->drop();
}


void ImageIrr::setColor(const Color &color)
{
    mColor.set(color.a, color.r, color.g, color.b);
}


void ImageIrr::draw(IMAGE_DRAW_MODE drawMode, UI32 flags, TREAL x, TREAL y,
                    const Color &color, const Rectangle *sourceRect)
{
    video::SColor irrcolor(color.a, color.r, color.g, color.b);
    draw(drawMode, flags, x, y, irrcolor, sourceRect);
}


void ImageIrr::draw(IMAGE_DRAW_MODE drawMode, UI32 flags, F32 x, F32 y,
                    const irr::video::SColor &color, const Rectangle *sourceRect)
{
    bool usingSrcArea = true;
    Rectangle srcArea;
    if (sourceRect)
        srcArea = *sourceRect;
    else if (!sourceRect && mUsingSourceRectangle)
        srcArea = mSourceRectangle;
    else
    {
        srcArea = Rectangle(0, 0, (TREAL)mWidth, (TREAL)mHeight);
        usingSrcArea = false;
    }

    video::S3DVertex vertices[4];
    if (flags & IF_COLOR)
    {
        // Set vertex color & alpha (IF_ALPHA flag is handled below separately)
        for (I32 a = 0; a < 4; ++a)
            vertices[a].Color = color;
    }
    else
    {
        for (I32 a = 0; a < 4; ++a)
            vertices[a].Color.set(0xffffffff);
    }
    if (!(flags & IF_ALPHA))
    {
        // ALPHA flag is not set, reset vertex alpha
        for (I32 a = 0; a < 4; ++a)
            vertices[a].Color.color |= 0xff000000;
    }
    else if (!(flags & IF_COLOR))
    {
        // ALPHA is set but not color flag, copy alpha values
        for (I32 a = 0; a < 4; ++a)
            vertices[a].Color.setAlpha(color.getAlpha());
    }

    irr::core::vector2df uv[2];
    uv[0] = mUV[0]; uv[1] = mUV[1];
    F32 halfWidth = mHalfWidth, halfHeight = mHalfHeight;
    if (usingSrcArea)
    {
        F32 uvW = uv[1].X - uv[0].X;
        F32 uvH = uv[1].Y - uv[0].Y;
        uv[0].X += uvW * srcArea.x / mWidth;
        uv[0].Y += uvH * srcArea.y / mHeight;
        uv[1].X = uv[0].X + uvW * srcArea.width / mWidth;
        uv[1].Y = uv[0].Y + uvH * srcArea.height / mHeight;
        halfWidth = srcArea.width * 0.5f;
        halfHeight = srcArea.height * 0.5f;
    }
    if (flags & IF_FLIP_HORIZ)
    {
        F32 t = uv[0].X;
        uv[0].X = uv[1].X;
        uv[1].X = t;
    }
    if (flags & IF_FLIP_VERT)
    {
        F32 t = uv[0].Y;
        uv[0].Y = uv[1].Y;
        uv[1].Y = t;
    }

    vertices[0].TCoords.set(uv[0].X, uv[0].Y);
    vertices[1].TCoords.set(uv[1].X, uv[0].Y);
    vertices[2].TCoords.set(uv[0].X, uv[1].Y);
    vertices[3].TCoords.set(uv[1].X, uv[1].Y);

    if (flags & IF_TRANSFORM)
    {
        F32 pivotX = -halfWidth, pivotY = -halfHeight; // transform center adjusted to top-left (default)
        if (flags & IF_ALIGN_RIGHT)
            pivotX = halfWidth;
        if (flags & IF_ALIGN_HORIZ_CENTER)
            pivotX = (mUsingCustomPivot ? mPivotX : halfWidth) - halfWidth;
        if (flags & IF_ALIGN_BOTTOM)
            pivotY = halfHeight;
        if (flags & IF_ALIGN_VERT_CENTER)
            pivotY = (mUsingCustomPivot ? mPivotY : halfHeight) - halfHeight;

        core::matrix4 transform;

        transform.setTranslation(core::vector3df(x, y, 0));
        if (flags & IF_ROTATE)
            transform.setRotationRadians(core::vector3df(0, 0, mAngle));
        if (flags & IF_SCALE)
        {
            core::matrix4 scale;
            scale.setScale(core::vector3df(mScaleX, mScaleY, 0));
            transform *= scale;
        }

        F32 topLeftX = -halfWidth - pivotX;
        F32 topLeftY = -halfHeight - pivotY;
        F32 bottomRightX = halfWidth - pivotX;
        F32 bottomRightY = halfHeight - pivotY;
        if (flags & IF_FORCE_INT)
        {
            topLeftX = ::floorf(topLeftX);
            topLeftY = ::floorf(topLeftY);
            bottomRightX = ::floorf(bottomRightX);
            bottomRightY = ::floorf(bottomRightY);
        }

        vertices[0].Pos.set(topLeftX, topLeftY, 0);
        vertices[1].Pos.set(bottomRightX, topLeftY, 0);
        vertices[2].Pos.set(topLeftX, bottomRightY, 0);
        vertices[3].Pos.set(bottomRightX, bottomRightY, 0);
        transform.transformVect(vertices[0].Pos);
        transform.transformVect(vertices[1].Pos);
        transform.transformVect(vertices[2].Pos);
        transform.transformVect(vertices[3].Pos);
    }
    else
    {
        F32 targetWidth = mTargetWidth, targetHeight = mTargetHeight;
        if (usingSrcArea && !mUsingExplicitTargetSize)
        {
            targetWidth = srcArea.width;
            targetHeight = srcArea.height;
        }
        F32 topLeftX = x, topLeftY = y; // top-left (default)
        if (flags & IF_ALIGN_RIGHT)
            topLeftX -= targetWidth;
        if (flags & IF_ALIGN_HORIZ_CENTER)
        {
            const F32 normalized = ((mUsingCustomPivot ? mPivotX : halfWidth) - halfWidth) / halfWidth; // range -1..1
            const F32 halfTargetWidth = targetWidth * 0.5f;
            topLeftX -= halfTargetWidth + halfTargetWidth * normalized;
        }
        if (flags & IF_ALIGN_BOTTOM)
            topLeftY -= targetHeight;
        if (flags & IF_ALIGN_VERT_CENTER)
        {
            const F32 normalized = ((mUsingCustomPivot ? mPivotY : halfHeight) - halfHeight) / halfHeight; // range -1..1
            const F32 halfTargetHeight = targetHeight * 0.5f;
            topLeftY -= halfTargetHeight + halfTargetHeight * normalized;
        }

        F32 bottomRightX = topLeftX + targetWidth;
        F32 bottomRightY = topLeftY + targetHeight;
        if (flags & IF_FORCE_INT)
        {
            topLeftX = ::floorf(topLeftX);
            topLeftY = ::floorf(topLeftY);
            bottomRightX = ::floorf(bottomRightX);
            bottomRightY = ::floorf(bottomRightY);
        }

        vertices[0].Pos.set(topLeftX, topLeftY, 0);
        vertices[1].Pos.set(bottomRightX, topLeftY, 0);
        vertices[2].Pos.set(topLeftX, bottomRightY, 0);
        vertices[3].Pos.set(bottomRightX, bottomRightY, 0);
    }

    mGraphics->batchImageDraw(mTexture, drawMode, mFlags & (IF_FILTER_LINEAR | IF_FILTER_LINEAR_MIPMAP | IF_WRAP_CLAMP_EDGE | IF_WRAP_REPEAT), vertices);
}


} // namespace turska
#endif // T2_USE_IRR
